#include "StdAfx.h"
#include "ChunkFileSerializer.h"
#include "SpecifiedChunk.h"

#include "TerrainBlockChunkItem.h"
#include "ChunkModel.h"

using namespace ChunkSystem;
using namespace Common;

const char*	m_pChunkItemStr[] = 
{
	"model",
	"speedtree",
	"particles",
	"navmesh",
	"terrain",
	"entity",
	"chunk"
};

ChunkFileSerializer::ChunkFileSerializer(void)
{
	::memset( m_pChunkItemFactories, 0, eEnd * 4 );

	//register all factory
	ChunkItemFactory* pFactory = NULL;
	pFactory = new TerrainBlockChunkFactory();
	m_pChunkItemFactories[eTerrain] = pFactory;

	pFactory = new InternalChunkFactory();
	m_pChunkItemFactories[eChunk] = pFactory;

	pFactory = new ChunkModelFactory();
	m_pChunkItemFactories[eModel] = pFactory;
}

ChunkFileSerializer::~ChunkFileSerializer(void)
{
	/*
	class SafeDeleteOp
	{
	public:
		void operator() (ChunkItemFactory* pChunkItemFactory )
		{
			if( pChunkItemFactory == NULL )
				return;

			delete pChunkItemFactory;
		}
	};

	std::for_each( m_ChunkItemFactories.begin(), m_ChunkItemFactories.end(), SafeDeleteOp() );

	m_ChunkItemFactories.clear();
	*/
	for( int i = eModel; i != eEnd; ++i )
	{
		ChunkItemFactory* pFactory = m_pChunkItemFactories[i];
		if( pFactory != NULL )
			delete pFactory;
	}
}

TiXmlElement* ChunkFileSerializer::GetChunkRoot( const String& strChunkFilePath , bool bCreate )
{
	size_t i = strChunkFilePath.rfind("/");
	if( i == -1 )
	{
		i = strChunkFilePath.rfind("\\");
		if( i == -1 )
		{
			assert( !"path format is invalid." );
			return NULL;
		}
	}

	size_t iDot = strChunkFilePath.rfind(".");
	if( iDot == -1 )
	{
		assert( !"path format is invalid." );
		return NULL;
	}

	String strChunkId = strChunkFilePath.substr( i + 1 , iDot - i - 1);
	ItrMapChunkNodes ptrChunk = m_ChunkDocNodes.find( strChunkId );
	if( ptrChunk != m_ChunkDocNodes.end()  )
	{
		if( ptrChunk->second.FirstChild().ToElement() == NULL )
			return NULL;
		return ptrChunk->second.FirstChild().ToElement();
	}

	TiXmlDocument* pDoc = new TiXmlDocument( strChunkFilePath );
	TiXmlHandle docHandle( pDoc );
	String strId = "";

	if( !pDoc->LoadFile() )
	{
		if( bCreate )
		{
			TiXmlNode* pRoot = pDoc->InsertEndChild( TiXmlElement("chunk") );
			pRoot->ToElement()->SetAttribute( "id",strChunkId );
		}
		else
			return NULL;
	}
	else
	{

		TiXmlHandle ptrRoot = docHandle.FirstChildElement();
		if( ptrRoot.ToElement() == NULL )
			return NULL;

		strId = ptrRoot.ToElement()->Attribute("id");
		if( strId.empty() )
		{
			assert(!("incorrect format"));
			return NULL;
		}
	}
	//m_ChunkDocNodes.insert( MapChunkNodes::value_type(strId, docHandle) );

	return docHandle.FirstChild().ToElement();
}

String ChunkFileSerializer::GetTag( ChunkItemType eType )
{
	assert( eType < eEnd );
	return m_pChunkItemStr[eType];
}

bool ChunkFileSerializer::CreateChunkItemFromFile( Chunk* pOwnerChunk, TiXmlElement* pChunkRoot, ChunkItemType eChunkType )
{
	//TODO generate factory
	assert( eChunkType < eEnd );

	ChunkItemFactory* pFactory = m_pChunkItemFactories[eChunkType];
	if( pFactory == NULL )
		return false;

	bool bRet = true;
	TiXmlHandle rootHandle(pChunkRoot);
	for( int i = 0 ; ; i++)
	{
		TiXmlElement* pChunkItemData = rootHandle.ChildElement( m_pChunkItemStr[eChunkType] , i ).ToElement();
		if( pChunkItemData == NULL )
			break;

		std::auto_ptr<ChunkItem> ptrNewChunkItem ( pFactory->Create( pOwnerChunk, pChunkItemData ) );
		if( ptrNewChunkItem.get() == NULL )
			continue;

		//if the chunkitem is an internal chunk we should put it into chunk loading queue again.
		if( ptrNewChunkItem->Load( pChunkItemData ) )
			pOwnerChunk->AddChunkItem(ptrNewChunkItem.release());
		else
		{
			//assert( !("faild to load chunk item") );
			bRet = false;
		}
	}

	return bRet;
}
